#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <time.h> 

#include "libradarssd.h"

unsigned long elapsed(struct timeval* begin, struct timeval* end){
    long seconds = end->tv_sec - begin->tv_sec;
    long microseconds = end->tv_usec - begin->tv_usec;
    return seconds*1e6 + microseconds;
}

int main(int argc, char *argv[]){
    if(argc <= 1){
        printf("argment error, format:./radar_recong.o start toa|measure time <-random> \n");
        return 0;
    }

    unsigned int mearsure_time = 1;
    if(argc == 3){
        char input[10];
        sscanf(argv[2],"%s",input);
        if(strcmp("-random",input)==0){
            mearsure_time = 0;
        }
        else{
            printf("argment error, format:./radar_recong.o start toa|measure time <-random> \n");
            return 0;
        }
    }

    u64 pri_type_range[4] = {1802175393,3604210499,5466294896,7267568690};

    struct radar_io_command command; //构建请求
    sscanf(argv[1],"%lu",&command.start_toa);
    command.data_count = 10;
    command.model_count = 1;
    command.model_id[0] = 4;

    struct timeval begin, end, slot_head, now; //slot_head和now用于计算实时IOPS
    u64 dispatch_time=0;
    u64 flash_read_time=0;
    u64 compute_time=0;
    gettimeofday(&begin, 0);
    //进行单次检索*************************************
    if(mearsure_time == 1){
        open_unvme();
        struct radar_io_command* result = (struct radar_io_command*)DMA_Send(NULL,(char*)&command,sizeof(struct radar_io_command),RADAR_SET_RECOG,0);
        close_unvme();

        // printf("Magic Number:0x%X\n",(unsigned)result->start_toa);
        // printf("RadarSSD result(TOA:%lu):\n",command.start_toa);
        // for(int i=0; i<1; i++)
        //     printf("[--match:%u\n",result->model_id[i]);
        //printf("Time:[%lu,%lu,%lu,%lu]\n",result->timestamp[0],result->timestamp[1],result->timestamp[2],result->timestamp[3]);
        dispatch_time += spend_time_us(result->timestamp[0],result->timestamp[1]);
        flash_read_time += spend_time_us(result->timestamp[1],result->timestamp[2]);
        compute_time += spend_time_us(result->timestamp[2],result->timestamp[3]);
    }
    else{ //多次检索测量精度******************************
        srand((unsigned)time(NULL));
        mearsure_time = command.start_toa;
        printf("Randomly test %u times\n",mearsure_time);
        unsigned int correct_time = 0;
        unsigned io_finished_in_slot = 0; //统计一个时间片内能进行多少次IO
        open_unvme();
        struct radar_io_command* result;
        gettimeofday(&slot_head, 0);
        for(int i=0; i<mearsure_time; i++){
            u64 start_toa = ((u64)rand()*10) % 7267568690;
            unsigned int type = 0;
            for(;type<4;type++){
                if(start_toa < pri_type_range[type])
                    break;
            }
            //printf("Compute:%lu, label:%u ",start_toa,type);

            //发送请求
            command.start_toa = start_toa;
            result = (struct radar_io_command*)DMA_Send(NULL,(char*)&command,sizeof(struct radar_io_command),RADAR_SET_RECOG,0);
            io_finished_in_slot++;
            //验证正确性
            //printf("result:%u\n",result->model_id[0]);
            if(result->start_toa != 0xAE86){
                //printf("Result Error!\n");
            }
            else{
                if(result->model_id[0] == type)
                    correct_time++;
                dispatch_time += spend_time_us(result->timestamp[0],result->timestamp[1]);
                flash_read_time += spend_time_us(result->timestamp[1],result->timestamp[2]);
                compute_time += spend_time_us(result->timestamp[2],result->timestamp[3]);
            }

            //判断时间片
            gettimeofday(&now, 0);
            unsigned elapse = elapsed(&slot_head, &now)/1000000;
            if(elapse>=1){
                printf("IOPS:%u\n",io_finished_in_slot);
                io_finished_in_slot=0;
                gettimeofday(&slot_head, 0);
            }
        }
        close_unvme();
        float rate = ((float)correct_time*100)/mearsure_time;
        printf("Measure %u time, correct:%u, rate:%.2f %%\n",mearsure_time,correct_time,rate);
    }
    gettimeofday(&end, 0);
    unsigned long elapse = elapsed(&begin, &end);
    printf("total elapsed %lu us(%.3f s) in host, average %lu us\n",elapse,elapsed(&begin, &end)/1000000.0,elapse/mearsure_time);
    printf("dispatch total spend %lu us, average %lu us\n",dispatch_time,dispatch_time/mearsure_time);
    printf("flash read total spend %lu us, average %lu us\n",flash_read_time,flash_read_time/mearsure_time);
    printf("compute total spend %lu us, average %lu us\n",compute_time,compute_time/mearsure_time);
    unsigned long other_time = elapse-dispatch_time-flash_read_time-compute_time;
    printf("others spend %lu us, average %lu us\n",other_time,other_time/mearsure_time);
    return 0;
}
